#include "bs_app_conf.h"
#include "bs_app.h"
//#include "bs_config.h"
#include <stdint.h>
#include <string.h>
#include "bs_protocol.h"

#define LOG_TAG        "[ICE]"
#include "log.h"


#define writer_jif                         (bs_jiffies)

extern const uint8_t bs_main_data[];
extern uint32_t bs_main_length;
extern S_Writer_t m_app;

uint32_t   burn_ok;
extern bs_led_dev_t led_ok;
extern bs_led_dev_t led_ng;

uint8_t    bs_dbg_recv_buf[512+4];   // 这个变量可以复用

static uint8_t    ice_input_buf_ch0[256*2];
static uint8_t    ice_input_buf_ch1[256*2];
static uint8_t    *ice_inputs_buf[2] = {ice_input_buf_ch0, ice_input_buf_ch1};
#if FS_TYPE
#else
static uint8_t    ice_file_buf_ch0[FILE_BLOCK_SIZE];
static uint8_t    ice_file_buf_ch1[FILE_BLOCK_SIZE];
static uint8_t    *ice_files_buf[2] = {ice_file_buf_ch0, ice_file_buf_ch1};
#endif

int bs_writer_init(bs_writer_ctx_t *ctx, unsigned char channel){
    // uint32_t fw_length = bs_main_length;
    // uint32_t fw_length = m_app.fw_len;
    uint32_t fw_length;
    int res = 0;

    burn_ok = 0;
    memset(ctx, 0, sizeof(bs_writer_ctx_t));
    ctx->channel = channel;
    ctx->schedu = IDLE;
    // ctx->schedu = LINKING;

    ctx->fw_data = ice_inputs_buf[channel];
    ctx->fw_base = ice_inputs_buf[channel];
    // ctx->fw_data = bs_main_data;

    ctx->cur_fw_addr = 0;
#if FS_TYPE
    res = bs_imgr_open_image(&ctx->fw_file);
    // f_open(&ctx->fw_file, fmware_name, FA_READ);
    f_read(&ctx->fw_file, &fw_length, 4, NULL);
#else
    // 初始化文件结构体，这里理应由 open函数来做
    // 文件的大小、内存映射buffer
    ctx->fw_file.f_owner = ctx;
    ctx->fw_file.start_blk = 0;
    ctx->fw_file.f_size = fw_length;// bs_main_length;
    ctx->fw_file.f_buf_base = ice_files_buf[channel];
    f2_open(&ctx->fw_file);

    f2_read(&ctx->fw_file, &fw_length, 4);
    ctx->fw_file.f_size = fw_length;
#endif
    ctx->fw_len = fw_length;
    bs_protocol_config(ctx, channel);
    ctx->timeout = writer_jif+LINK_TIME_OUT;
    return res;
}


// 返回1：falsh busy 或者 超时
static int bs_writer_wait_busy(bs_writer_ctx_t *ctx)
{
    uint8_t bs_dbg_recv_buf[2];
    uint8_t tmp_u8;
    ctx->tmp_send_buf[0] = 0x3c;
    ctx->tmp_send_buf[1] = (unsigned char)~(0x3c);
    bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
    bs_protocol_read(ctx, bs_dbg_recv_buf,2);
    if(bs_dbg_recv_buf[0] != 0x3c || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
        ctx->schedu = FAILED_READ_ICE_STATE_REG;
        goto error;
    }
    bs_protocol_read(ctx, bs_dbg_recv_buf,2);
    if((bs_dbg_recv_buf[0]&0xff) != ((~bs_dbg_recv_buf[1])&0xff)){
        ctx->schedu = FAILED_READ_ICE_STATE_REG;
        goto error;
    }
    tmp_u8 = bs_dbg_recv_buf[0];
    bs_protocol_read(ctx, bs_dbg_recv_buf,2);
    if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
    }else{
        ctx->schedu = FAILED_READ_ICE_STATE_REG;
        goto error;
    }
    if(tmp_u8 == 0){
        goto success;
    }

    if(ctx->timeout == 0){
        ctx->schedu = FAILED_READ_ICE_STATE_REG;
        goto error;
    }
    ctx->timeout--;
error:
    return 1;
success:
    return 0;
}


/*!
    \brief      烧录过程
    \param[in]  none
    \param[out] none
    \retval     0: success
*/
int bs_writer_test(bs_writer_ctx_t *ctx)
{
    // unsigned char tmp_u8 = 0;
    unsigned char ice_state_reg =0;
    uint32_t cur_fw_addr = 0;
    uint32_t cur_fw_len = 0;
    // uint32_t brk_point;

    
#ifndef BOOTLOADER_PRJ
    switch (ctx->schedu) {
        case IDLE:
            // if(ctx->timeout-- > 0)
            // {
            //     break;
            // }
            // ctx->tmp_send_buf[0] = 0xA4;
            // ctx->tmp_send_buf[1] = (unsigned char)~(0xA4);
            // bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            // bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            // if(bs_dbg_recv_buf[0] != 0xA4 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
            //     ctx->schedu = WRITER_ERROR;
            // }
            // ctx->timeout = 100;
            // delay_1ms(1);
        break;

        case LINKING:
            if (writer_jif > ctx->timeout) {
                ctx->schedu = LINKING_TIMEOUT;
                break;
            }
            ctx->tmp_send_buf[0] = 0xFF;
            ctx->tmp_send_buf[1] = 0x7F;
            ctx->tmp_send_buf[2] = 0xA5;
            ctx->tmp_send_buf[3] = (unsigned char)~(0xA5);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,4);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            // link_ok = 0;
            if(bs_dbg_recv_buf[0] == 0xA5 && bs_dbg_recv_buf[1] == ((~0xA5)&0xff)){
                ctx->timeout = 10000;
                ctx->schedu = WAIT_BEFORE_ERASE;
                LOGI("ICE CH_%d linked", ctx->channel);
            }else{
            }
        break;

        case WAIT_BEFORE_ERASE:
            // wait FLASH busy
            if (!bs_writer_wait_busy(ctx))
            {
                ctx->schedu = RELEASET_WRITE_PROTECT;
            }
        break;

        case RELEASET_WRITE_PROTECT:				
            /* release write protect. */
            ctx->tmp_send_buf[0] = 0x70;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x70);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x70 && bs_dbg_recv_buf[1] == ctx->tmp_send_buf[1]){
                ctx->schedu = ERASE;
            }else{
                ctx->schedu = WAIT_ERASE_ERR;
            }
        break;

        case ERASE:
            ctx->tmp_send_buf[0] = 0x73;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x73);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x73 && bs_dbg_recv_buf[1] == ctx->tmp_send_buf[1]){
                ctx->schedu = WAIT_ERASE;
            }else{
                ctx->schedu = WAIT_ERASE_ERR;
            }
        break;

        case WAIT_ERASE_ERR:
            ctx->schedu = WRITER_ERROR;
        break;

        case WAIT_ERASE:
            ctx->tmp_send_buf[0] = 0x3c;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x3c);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x3c && bs_dbg_recv_buf[1] == ctx->tmp_send_buf[1]){
                //m_app.sent_pkg.sent_pkg_func.m_PayLSize = 2;
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if((bs_dbg_recv_buf[0]&0xff) != ((~bs_dbg_recv_buf[1])&0xff)){
                    ctx->schedu = WRITER_ERROR;
                }
                ice_state_reg = bs_dbg_recv_buf[0];
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
                    if(ice_state_reg == 0x00){
                        ctx->schedu = WRITE_FLASH;  // TODO
                    }
                }else{
                }
            } 
        break;

        case LINKED:
            ctx->tmp_send_buf[0] = 0xA4;
            ctx->tmp_send_buf[1] = (unsigned char)(~(0xA4));
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);

        break;

        case FAILED_READ_ICE_STATE_REG:
            ctx->schedu = WRITER_ERROR;
        break;

        case FAILED_DISABLE_WRITE_PROTECT:
        break;

        case WRITE_FLASH:
            if(ctx->fw_len <= 0){
                ctx->schedu = FINISH;
                break;
            }
            // 有可能固件数据没有准备好，如果准备好就 write sram，否则空闲
            cur_fw_len = (ctx->fw_len > 256) ? 255:(ctx->fw_len - 1);
            ctx->cur_fw_len = cur_fw_len;
            // 先提交请求
            ctx->schedu = WRITE_FLASH_WAIT_DATA1;
            if (bs_fw_fill_data(ctx, ctx->cur_fw_len+1) == 0) ctx->schedu = WRITE_FLASH_DATA_READY1;
        break;

        case WRITE_FLASH_WAIT_DATA1:
            // 查询数据是否准备好
            if(bs_fw_fill_data(ctx, ctx->cur_fw_len+1) == 0) {
                // 数据准备好了
                ctx->schedu = WRITE_FLASH_DATA_READY1;
            } else {
                // break;
                // 发送心跳包，防止掉线
                ctx->tmp_send_buf[0] = 0xA4;
                ctx->tmp_send_buf[1] = (unsigned char)~(0xA4);
                bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] != 0xA4 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                    ctx->schedu = WRITER_ERROR;
                }
            }
        break;
        
        case WRITE_FLASH_DATA_READY1:
            // set SRAM A addr and len
            cur_fw_len = ctx->cur_fw_len;
            ctx->tmp_send_buf[0] = 0xB1;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB1);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB1 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->tmp_send_buf[0] = cur_fw_len;
            ctx->tmp_send_buf[1] = ~(cur_fw_len);
            ctx->tmp_send_buf[2] = (0x20&0xff);
            ctx->tmp_send_buf[3] = ~((0x20&0xff));
            ctx->tmp_send_buf[4] = (0x00&0xff);
            ctx->tmp_send_buf[5] = ~(0x00&0xff);
            ctx->tmp_send_buf[6] = (0x00&0xff);
            ctx->tmp_send_buf[7] = ~(((0x00)&0xff));
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,8);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }

            // write SRAM A
            ctx->tmp_send_buf[0] = 0xB5;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB5);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB5 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_WRITE_SRAM_A;
                break;
            }
            bs_protocol_write_async(ctx, ctx->fw_data, cur_fw_len, 0);
            // ctx->fw_data += (cur_fw_len + 1);
            ctx->fw_len -= (cur_fw_len + 1);
            // ctx->cur_fw_len = cur_fw_len;

            // async wait DMA transmit completely...
            ctx->schedu = WAIT_WRITE_FLASH1;
            ctx->timeout = BS_PROTOCOL_TIMEOUT;
            DBG_IDLE_SET
            break;

        case WAIT_WRITE_FLASH1:
            // wait DMA transmit
            if (bs_protocol_ioctl(ctx, IOC_WR_END))
            {
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
                    // ctx->schedu = WRITE_FLASH2;
                    DBG_IDLE_CLR
                    // read sram 0x35
                    ctx->tmp_send_buf[0] = 0x35;
                    ctx->tmp_send_buf[1] = (unsigned char)~(0x35);
                    bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
                    bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                    if(bs_dbg_recv_buf[0] != 0x35 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                        ctx->schedu = FAILED_WRITE_SRAM_A;
                        break;
                    }
                    bs_protocol_read_async(ctx, ctx->tmp_send_buf, ctx->cur_fw_len);
                    ctx->schedu = WRITE_READBACK_A_WAIT;
                    ctx->timeout = BS_PROTOCOL_TIMEOUT;
                    DBG_IDLE_SET
                    break;
                }else{
                    ctx->schedu = FAILED_WRITE_SRAM_A;
                    break;
                }
            }
            break;

        case WRITE_READBACK_A_WAIT:
            // wait DMA transmit
            if (bs_protocol_ioctl(ctx, IOC_RD_END))
            {
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
                    DBG_IDLE_CLR
                    ctx->schedu = WRITE_FLASH2;
                    // 回读后 对比 写入的数据, 发送指针是没有反码；
                    if (memcmp(ctx->drv->tx_buf, ctx->drv->rx_buf, ctx->cur_fw_len*2+2) != 0) {
                        ctx->schedu = FAILED_READBACK_A;
                        break;
                    }
                }else{
                    ctx->schedu = FAILED_WRITE_SRAM_A;
                }
            }
        break;

        case WRITE_FLASH2:
            // set FLASH addr and len
            cur_fw_len = ctx->cur_fw_len;
            cur_fw_addr = ctx->cur_fw_addr;
            
            ctx->tmp_send_buf[0] = 0xB1;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB1);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB1 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->tmp_send_buf[0] = cur_fw_len;
            ctx->tmp_send_buf[1] = ~(cur_fw_len);
            ctx->tmp_send_buf[2] = ((cur_fw_addr>>1)&0xff);
            ctx->tmp_send_buf[3] = ~(((cur_fw_addr>>1)&0xff));
            ctx->tmp_send_buf[4] = (((cur_fw_addr>>1) >> 8)&0xff);
            ctx->tmp_send_buf[5] = ~((((cur_fw_addr>>1) >> 8)&0xff));
            ctx->tmp_send_buf[6] = (((cur_fw_addr>>1) >> 16)&0xff);
            ctx->tmp_send_buf[7] = ~((((cur_fw_addr>>1) >> 16)&0xff));
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,8);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->timeout = BS_PROTOCOL_TIMEOUT;
            ctx->schedu = WAIT_WRITE_FLASH2;
            DBG_IDLE_SET
        break;

        case WAIT_WRITE_FLASH2:
            // wait FLASH busy
            if (!bs_writer_wait_busy(ctx))
            {
                ctx->schedu = WRITE_FLASH3;
                DBG_IDLE_CLR
            }
        break;

        case WRITE_FLASH3:
            // disable write protect
            ctx->tmp_send_buf[0] = 0x70;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x70);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x70 && bs_dbg_recv_buf[1] == ctx->tmp_send_buf[1]){
            }else{
                ctx->schedu = FAILED_DISABLE_WRITE_PROTECT;
                break;
            }
            
            // write SRAM A to FLASH
            ctx->tmp_send_buf[0] = 0xB3;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB3);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB3 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_WRITE_SRAMA_TO_FLASH;
                break;
            }
            ctx->tmp_send_buf[0] = 0x20;
            ctx->tmp_send_buf[1] = ~(0x20);
            ctx->tmp_send_buf[2] = 0x00;
            ctx->tmp_send_buf[3] = ~(0x00);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,4);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_WRITE_SRAMA_TO_FLASH;
                break;
            }
            ctx->cur_fw_addr += (ctx->cur_fw_len + 1);

            if(ctx->fw_len <= 0){
                ctx->schedu = FINISH;
                break;
            }

            // 有可能固件数据没有准备好，如果准备好就 write sram，否则空闲
            cur_fw_len = (ctx->fw_len > 256) ? 255:(ctx->fw_len - 1);
            // 先提交请求
            ctx->cur_fw_len = cur_fw_len;
            ctx->schedu = WRITE_FLASH_WAIT_DATA2;
            if (bs_fw_fill_data(ctx, ctx->cur_fw_len+1) == 0) ctx->schedu = WRITE_FLASH_DATA_READY2;
            DBG_IDLE_SET
        break;

        case WRITE_FLASH_WAIT_DATA2:
            // 查询数据是否准备好
            if(bs_fw_fill_data(ctx, ctx->cur_fw_len+1) == 0) {
                // 数据准备好了
                ctx->schedu = WRITE_FLASH_DATA_READY2;
            } else {
                // break;
                // 发送心跳包，防止掉线
                ctx->tmp_send_buf[0] = 0xA4;
                ctx->tmp_send_buf[1] = (unsigned char)~(0xA4);
                bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] != 0xA4 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                    ctx->schedu = WRITER_ERROR;
                }
            }
        break;

        case WRITE_FLASH_DATA_READY2:
            DBG_IDLE_CLR
            // set SRAM B addr and len
            cur_fw_len = ctx->cur_fw_len;
            ctx->tmp_send_buf[0] = 0xB1;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB1);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB1 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->tmp_send_buf[0] = cur_fw_len;
            ctx->tmp_send_buf[1] = ~(cur_fw_len);
            ctx->tmp_send_buf[2] = (0x20&0xff);
            ctx->tmp_send_buf[3] = ~((0x20&0xff));
            ctx->tmp_send_buf[4] = (0x01&0xff);
            ctx->tmp_send_buf[5] = ~(0x01&0xff);
            ctx->tmp_send_buf[6] = (0x00&0xff);
            ctx->tmp_send_buf[7] = ~(((0x00)&0xff));
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,8);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            
            // write SRAM B
            ctx->tmp_send_buf[0] = 0xB5;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB5);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB5 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_WRITE_SRAM_B;
                break;
            };
            bs_protocol_write_async(ctx, ctx->fw_data, cur_fw_len, 1);
            // ctx->fw_data += (cur_fw_len + 1);
            ctx->fw_len -= (cur_fw_len + 1);
            // ctx->cur_fw_len = cur_fw_len;

            // async wait DMA transmit completely...
            ctx->schedu = WAIT_WRITE_FLASH3;
            ctx->timeout = BS_PROTOCOL_TIMEOUT;
            DBG_IDLE_SET
        break;

        case WAIT_WRITE_FLASH3:
            // wait DMA transmit
            if (bs_protocol_ioctl(ctx, IOC_WR_END))
            {
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
                    DBG_IDLE_CLR
                    // read sram 0x35
                    ctx->tmp_send_buf[0] = 0x35;
                    ctx->tmp_send_buf[1] = (unsigned char)~(0x35);
                    bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
                    bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                    if(bs_dbg_recv_buf[0] != 0x35 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                        ctx->schedu = FAILED_WRITE_SRAM_A;
                        break;
                    }
                    bs_protocol_read_async(ctx, ctx->tmp_send_buf, ctx->cur_fw_len);
                    ctx->schedu = WRITE_READBACK_B_WAIT;
                    ctx->timeout = BS_PROTOCOL_TIMEOUT;
                    DBG_IDLE_SET
                }else{
                    ctx->schedu = FAILED_WRITE_SRAM_A;
                    break;
                }
            }
        break;

        case WRITE_READBACK_B_WAIT:
            // wait DMA transmit
            if (bs_protocol_ioctl(ctx, IOC_RD_END))
            {
                bs_protocol_read(ctx, bs_dbg_recv_buf,2);
                if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
                    DBG_IDLE_CLR
                    ctx->schedu = WRITE_FLASH4;
                    // 回读后 对比 写入的数据, 发送指针是没有反码；
                    if (memcmp(ctx->drv->tx_buf, ctx->drv->rx_buf, ctx->cur_fw_len*2+2) != 0) {
                        ctx->schedu = FAILED_READBACK_A;
                        break;
                    }
                }else{
                    ctx->schedu = FAILED_WRITE_SRAM_B;
                }
            }
        break;

        case WRITE_FLASH4:
            // set FLASH addr and len
            cur_fw_len = ctx->cur_fw_len;
            cur_fw_addr = ctx->cur_fw_addr;

            ctx->tmp_send_buf[0] = 0xB1;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB1);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB1 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->tmp_send_buf[0] = cur_fw_len;
            ctx->tmp_send_buf[1] = ~(cur_fw_len);
            ctx->tmp_send_buf[2] = ((cur_fw_addr>>1)&0xff);
            ctx->tmp_send_buf[3] = ~(((cur_fw_addr>>1)&0xff));
            ctx->tmp_send_buf[4] = (((cur_fw_addr>>1) >> 8)&0xff);
            ctx->tmp_send_buf[5] = ~((((cur_fw_addr>>1) >> 8)&0xff));
            ctx->tmp_send_buf[6] = (((cur_fw_addr>>1) >> 16)&0xff);
            ctx->tmp_send_buf[7] = ~((((cur_fw_addr>>1) >> 16)&0xff));
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,8);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_SET_ADDR_AND_LEN;
                break;
            }
            ctx->timeout = BS_PROTOCOL_TIMEOUT;
            ctx->schedu = WAIT_WRITE_FLASH4;
            DBG_IDLE_SET
        break;

        case WAIT_WRITE_FLASH4:
            // wait FLASH busy
            if (!bs_writer_wait_busy(ctx))
            {
                ctx->schedu = WRITE_FLASH5;
                DBG_IDLE_CLR
            }
        break;

        case WRITE_FLASH5:
            // disable write protect
            ctx->tmp_send_buf[0] = 0x70;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x70);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x70 && bs_dbg_recv_buf[1] == ctx->tmp_send_buf[1]){
            }else{
                ctx->schedu = FAILED_DISABLE_WRITE_PROTECT;
                break;
            }

            // write SRAM B to FLASH
            ctx->tmp_send_buf[0] = 0xB3;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB3);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB3 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = FAILED_WRITE_SRAMB_TO_FLASH;
                break;
            }
            ctx->tmp_send_buf[0] = 0x20;
            ctx->tmp_send_buf[1] = ~(0x20);
            ctx->tmp_send_buf[2] = 0x01;
            ctx->tmp_send_buf[3] = ~(0x01);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,4);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = FAILED_WRITE_SRAMB_TO_FLASH;
                break;
            }
            ctx->cur_fw_addr += (ctx->cur_fw_len + 1);
            
            if(ctx->fw_len <= 0){
                ctx->schedu = FINISH;
                ctx->timeout = BS_PROTOCOL_TIMEOUT;
                break;
            }
            ctx->schedu = WRITE_FLASH;
        break;

        case FINISH:
            // wait FLASH busy
            if (bs_writer_wait_busy(ctx)) break;
            LOGI("IC CH_%d download OK", ctx->channel);

            // 退出 ICE
            ctx->tmp_send_buf[0] = 0xb0;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xb0);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB0 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            ctx->tmp_send_buf[0] = 0xA7;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xA7);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf, 2);
            bs_protocol_read(ctx, bs_dbg_recv_buf, 2);
           if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
           } else {
               ctx->schedu = EXIT_ERROR;
               break;
           }
           ctx->schedu = FINISH_RESET;
        break;
    
        case FINISH_RESET:
            // 重连
            ctx->tmp_send_buf[0] = 0xFF;
            ctx->tmp_send_buf[1] = 0x7F;
            ctx->tmp_send_buf[2] = 0xA5;
            ctx->tmp_send_buf[3] = (unsigned char)~(0xA5);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,4);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0xA5 && bs_dbg_recv_buf[1] == ((~0xA5)&0xff)) {
            } else {break;}

            ctx->tmp_send_buf[0] = 0x91;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x91);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0x91 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            
            ctx->schedu = WRITE_OVER;
            bs_imgr_close_image(&ctx->fw_file);
            if (++burn_ok == 2) bs_led_ctl(&led_ok, LED_ON, 4);
            break;

#if 0
            // 先停下来: 先不要发这个命令
            // ctx->tmp_send_buf[0] = 0x92;
            // ctx->tmp_send_buf[1] = (unsigned char)~(0x92);
            // bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            // bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            // if(bs_dbg_recv_buf[0] != 0x92 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
            //     ctx->schedu = EXIT_ERROR;
            //     break;
            // }

            // 设置断点
            ctx->tmp_send_buf[0] = 0xB2;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xB2);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xB2 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            brk_point = ctx->int_point;
            ctx->tmp_send_buf[0] = brk_point&0xFF;
            ctx->tmp_send_buf[1] = ~(brk_point&0xFF);
            ctx->tmp_send_buf[2] = ((brk_point >> 8)&0xFF);
            ctx->tmp_send_buf[3] = ~((brk_point >> 8)&0xFF);
            ctx->tmp_send_buf[4] = ((brk_point >> 16)&0xFF);;
            ctx->tmp_send_buf[5] = ~((brk_point >> 16)&0xFF);
            ctx->tmp_send_buf[6] = 0;
            ctx->tmp_send_buf[7] = 0xFF;
            ctx->tmp_send_buf[8] = 0;
            ctx->tmp_send_buf[9] = 0xFF;
            ctx->tmp_send_buf[10] = 0;
            ctx->tmp_send_buf[11] = 0xFF;
            ctx->tmp_send_buf[12] = 0;
            ctx->tmp_send_buf[13] = 0xFF;
            ctx->tmp_send_buf[14] = 0;
            ctx->tmp_send_buf[15] = 0xFF;
            ctx->tmp_send_buf[16] = 0;
            ctx->tmp_send_buf[17] = 0xFF;
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf, 18);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
            }else{
                ctx->schedu = EXIT_ERROR;
                break;
            }

            // 回读断点
            ctx->tmp_send_buf[0] = 0x32;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x32);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0x32 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            bs_protocol_read(ctx, bs_dbg_recv_buf,20);

            // 全速运行
            ctx->tmp_send_buf[0] = 0x91;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x91);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0x91 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            ctx->timeout = bs_jiffies + 200;
            ctx->user_var = 5;
            if (++burn_ok == 2) bs_led_ctl(&led_ok, LED_ON, 4);
            
            ctx->schedu = WAIT_BRK_POINT;
            break;

// loop:
//             // 停下来
//             ctx->tmp_send_buf[0] = 0x92;
//             ctx->tmp_send_buf[1] = (unsigned char)~(0x92);
//             bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
//             bs_protocol_read(ctx, bs_dbg_recv_buf,2);
//             if(bs_dbg_recv_buf[0] != 0x92 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
//                 ctx->schedu = EXIT_ERROR;
//                 break;
//             }

//             // 读取PC
//             GPIO_TG(GPIOB) = GPIO_PIN_0;
//             ctx->tmp_send_buf[0] = 0xB1;
//             ctx->tmp_send_buf[1] = (unsigned char)~(0xB1);
//             bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
//             bs_protocol_read(ctx, bs_dbg_recv_buf,2);
//             if(bs_dbg_recv_buf[0] != 0xB1 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
//                 ctx->schedu = FAILED_SET_ADDR_AND_LEN;
//                 break;
//             }
//             cur_fw_addr = 0x8100;
//             ctx->tmp_send_buf[0] = 2;
//             ctx->tmp_send_buf[1] = ~(2);
//             ctx->tmp_send_buf[2] = (cur_fw_addr&0xff);
//             ctx->tmp_send_buf[3] = ~(cur_fw_addr&0xff);
//             ctx->tmp_send_buf[4] = ((cur_fw_addr >> 8)&0xff);
//             ctx->tmp_send_buf[5] = ~((cur_fw_addr >> 8)&0xff);
//             ctx->tmp_send_buf[6] = ((cur_fw_addr >> 16)&0xff);
//             ctx->tmp_send_buf[7] = ~((cur_fw_addr >> 16)&0xff);
//             bs_protocol_write_sync(ctx, ctx->tmp_send_buf,8);
//             bs_protocol_read(ctx, bs_dbg_recv_buf,2);
//             if(bs_dbg_recv_buf[0] == 0x5A && bs_dbg_recv_buf[1] == 0xA5){
//             }else{
//                 ctx->schedu = FAILED_SET_ADDR_AND_LEN;
//                 break;
//             }

//             // 读寄存器
//             ctx->tmp_send_buf[0] = 0x34;
//             ctx->tmp_send_buf[1] = (unsigned char)~(0x34);
//             bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
//             bs_protocol_read(ctx, bs_dbg_recv_buf,2);
//             if(bs_dbg_recv_buf[0] != 0x34 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
//                 ctx->schedu = EXIT_ERROR;
//                 break;
//             }
//             bs_protocol_read(ctx, bs_dbg_recv_buf,8);
//             LOGI("PC: 0x%x", (uint32_t)((bs_dbg_recv_buf[2]<<8) + bs_dbg_recv_buf[0]))

//             // 全速
//             ctx->tmp_send_buf[0] = 0x91;
//             ctx->tmp_send_buf[1] = (unsigned char)~(0x91);
//             bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
//             bs_protocol_read(ctx, bs_dbg_recv_buf,2);
//             if(bs_dbg_recv_buf[0] != 0x91 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
//                 ctx->schedu = EXIT_ERROR;
//                 break;
//             }

//             delay_1ms(4);

//             goto loop;
        break;

        case WAIT_BRK_POINT:
            ctx->tmp_send_buf[0] = 0xA4;
            ctx->tmp_send_buf[1] = (unsigned char)~(0xA4);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0xA4 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = WRITER_ERROR;
            }
            delay_1ms(1);
            // if(ctx->user_var == 0) break;
            if (bs_jiffies > ctx->timeout) ctx->schedu = WAIT_BRK_POINT2;
        break;

        case WAIT_BRK_POINT2:
            // 延时到了，则全速运行，
            ctx->user_var--;
            ctx->tmp_send_buf[0] = 0x91;
            ctx->tmp_send_buf[1] = (unsigned char)~(0x91);
            bs_protocol_write_sync(ctx, ctx->tmp_send_buf,2);
            bs_protocol_read(ctx, bs_dbg_recv_buf,2);
            if(bs_dbg_recv_buf[0] != 0x91 || bs_dbg_recv_buf[1] != ctx->tmp_send_buf[1]){
                ctx->schedu = EXIT_ERROR;
                break;
            }
            ctx->timeout = bs_jiffies + 200;
            ctx->schedu = WAIT_BRK_POINT;
        break;
#endif
#endif	
        case LINKING_TIMEOUT:
        case FAILED_READBACK_A:
        case FAILED_READBACK_B:
        case FAILED_WRITE_SRAM_A:
        case FAILED_SET_ADDR_AND_LEN:
        case WRITER_WR_TIME_OUT:
        case WRITER_RD_TIME_OUT:
        case EXIT_ERROR:
            LOGE("channel: %d, Error: %s", ctx->channel, sched2str[ctx->schedu]);
            ctx->schedu = WRITER_ERROR;
        break;

        case WRITER_ERROR:
            DBG_BSY_TOGGLE
            bs_led_ctl(&led_ng, LED_SHINE, 5);
            ctx->schedu = WRITE_OVER;
            // bs_writer_init(ctx, ctx->channel);
            // ctx->schedu = LINKING;
        break;

        case WRITE_OVER:
            ctx->schedu = IDLE;
            
        break;
				


        default:
        break;
        }
		return 0;
}


/*!
    \brief      获取固件解密后的数据, 这个接口应该是异步的，因为数据有可能没有准备好
    \param[in]  size 只能为 256
    \param[out] none
    \retval     0: success，1：busy
*/
int bs_fw_fill_data(bs_writer_ctx_t *ctx, int size)
{
    int status = 1;
#if FS_TYPE
    status = f_read(&ctx->fw_file, ctx->fw_data, size, NULL);
#else
    status = f2_bread(&ctx->fw_file, ctx->fw_data, size);
#endif
    // return status;
    // 最大 256 byte，所以
    // 保证缓冲区至少存在 256*2 byte 的数据，如果数据不够就读取
    // 先向 bufferA 
    // 第一次进来应该填满，但是下次它读取多少呢？这个不好
    // 这里其实是两个接口：第一次提交，第二次查询
    return status;
}
